using System;
using TestCases.CompareAssert.Core.Builders;
using TestCases.CompareAssert.Core.Interfaces;
using TestCases.CompareAssert.Core.Selectors;
using TestCases.Utils;

namespace TestCases.CompareAssert.Core.Comparers.Generics
{
    public class EquatableComparer: GenericComparer
    {
        public const string IdentifiableName = "EquatableComparer";
        private static readonly EquatableComparer _instance = new EquatableComparer();

// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
// ReSharper disable EmptyConstructor
        static EquatableComparer()
// ReSharper restore EmptyConstructor
        {
        }

        public EquatableComparer() : base(new CovariantInterfacesSelector("IEquatable`1"))
        {
        }

        public static EquatableComparer Instance
        {
            get { return _instance; }
        }        
        
        public override string Name
        {
            get { return IdentifiableName; }
        }

        public override IResultBuilder Compare(ICompareContext context)
        {
            var result = CompareViaInterfaces(context);
            if (result != null)
            {
                return result;
            }
            return this.IsNotApplicable(context).Left.IsNot("IEquatable<{RType}>");
        }

        public override IResultBuilder CompareVia(Type interfaceType, ICompareContext context)
        {
            return this.IsBoolResult(context.LValue.InvokeMethod<bool>(interfaceType, "Equals", context.RValue), context).
                ForEquals("<{LPath}>.Equals(<{RPath}>) is true [{LValue}.Equals({RValue}) == true].").
                ForNotEquals("<{LPath}>.Equals(<{RPath}>) is false [{LValue}.Equals({RValue}) == false].");
        }
    }
}